package cn.fz.demo02.config;

import cn.fz.demo02.dao.UserRepository;
import cn.fz.demo02.domain.po.Role;
import cn.fz.demo02.domain.po.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.security.core.userdetails.User.UserBuilder;

import static org.springframework.security.core.userdetails.User.withUsername;

/**
 * 4. Spring Security 配置
 * 要使用 Spring Security 进行用户认证，我们需要配置 SecurityConfig，并实现自定义的 UserDetailsService 来与数据库中的用户信息进行集成。
 *
 * 4.1 自定义 UserDetailsService
 * 想从数据库加载用户信息，就需要创建一个自定义的 UserDetailsService 实现类，它的主要作用：
 *
 * 用户认证：
 * UserDetailsService 负责从数据源（如数据库、LDAP等）中加载用户特定的安全信息，包括用户名、密码和权限（角色）。
 * Spring Security 使用 UserDetailsService 来验证用户提供的凭据是否正确。
 * 用户授权：
 * 加载用户的权限信息，以便在认证成功后进行授权检查。
 * 权限信息通常包括用户的角色（如 ROLE_ADMIN, ROLE_USER 等），这些角色用于控制用户可以访问的资源和操作。
 * 原文链接：https://blog.csdn.net/u014390502/article/details/143064075
 */
@Service
@Slf4j
public class CustomUserDetailsService implements UserDetailsService {
    private final UserRepository userRepository;

    public CustomUserDetailsService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    /**
     * 这里，我们根据数据库中的用户信息加载用户，并将角色转换为 Spring Security 能识别的格式。
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("用户不存在"));
        UserBuilder builder = withUsername(user.getUsername());
        builder.password(user.getPassword());
        builder.roles(user.getRoles().stream().map(Role::getName).toArray(String[]::new));
        return builder.build();
    }
}
